package org.softmed.rest.editor.comps.utils;

import java.awt.Color;
import java.awt.Dialog;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.Border;

import net.miginfocom.swing.MigLayout;

import org.restlet.data.Response;
import org.restlet.resource.StringRepresentation;
import org.softmed.rest.editor.EditorUtil;
import org.softmed.rest.editor.FilePathAware;
import org.softmed.rest.editor.FilePathProvider;
import org.softmed.rest.editor.commons.SwingUtil;
import org.softmed.rest.editor.commons.URIProvider;
import org.softmed.rest.editor.comps.SimpleEditor;
import org.softmed.rest.editor.comps.browser.PagedListPanel;
import org.softmed.rest.editor.comps.browser.SelectionListener;
import org.softmed.rest.editor.comps.full.getDeletePanel;
import org.softmed.swing.IconManager;

public class FieldPanel extends JPanel implements ActionListener, KeyListener,
		SelectionListener, FilePathAware {

	JTextField id = new JTextField();
	JButton createNew = new JButton(IconManager.add);
	JButton find = new JButton(IconManager.search);
	JButton browse = new JButton(IconManager.searchInList);

	JButton remove = new JButton(IconManager.redMinus);

	JPanel panel = new JPanel();

	JPanel content = new JPanel();
	JPanel inside = new JPanel();

	SimpleEditor editor;
	String uriFieldName;
	SimpleEditor parentEditor;
	private Class editorClass;
	private JDialog dialog;
	private FilePathProvider filePathProvider;

	public FieldPanel(String label, String uriFieldName, Class editorClass,
			SimpleEditor parent) throws Throwable {
		// setBorder(BorderFactory.createEtchedBorder());
		// setBackground(Color.YELLOW);

		setButtonBorder(BorderFactory.createLineBorder(Color.GRAY));

		// id.setBorder(BorderFactory.createLineBorder(Color.BLACK));

		// createNew.setBackground(Color.WHITE);
		// find.setBackground(Color.WHITE);
		// browse.setBackground(Color.WHITE);
		// remove.setBackground(Color.WHITE);

		createNew.setToolTipText("Create new object and set as this field");
		find
				.setToolTipText("Get the object with the id refered in the text field");
		browse.setToolTipText("Browse for an object to set in this field");
		id.setToolTipText("Write the id of the object to set in the field");

		this.editorClass = editorClass;
		this.parentEditor = parent;
		this.uriFieldName = uriFieldName;

		if (!SimpleEditor.class.isAssignableFrom(editorClass))
			throw new RuntimeException(
					"Editor class for field must be a SimpleEditor");

		if (!getDeletePanel.class.isAssignableFrom(editorClass))
			throw new RuntimeException(
					"Editor class for field must implement getDeletePanel");

		SwingUtil.setSize(remove, EditorUtil.buttonHeightAndWidth,
				EditorUtil.buttonHeightAndWidth);

		SwingUtil.setSize(createNew, EditorUtil.buttonHeightAndWidth,
				EditorUtil.buttonHeightAndWidth);
		SwingUtil.setSize(find, EditorUtil.buttonHeightAndWidth,
				EditorUtil.buttonHeightAndWidth);
		SwingUtil.setSize(browse, EditorUtil.buttonHeightAndWidth,
				EditorUtil.buttonHeightAndWidth);

		MigLayout layout = new MigLayout("left,insets 0,gap 0");
		panel.setLayout(layout);
		// panel.setBackground(Color.BLUE);
		Insets insets = new java.awt.Insets(0, 0, 0, 0);
		JLabel title = new JLabel(label);
		title.setFont(SwingUtil.editorTitleFont);

		panel.add(title, "w 95!");

		// panel.add(createNew);
		// panel.add(Box.createHorizontalStrut(5));
		// panel.add(browse, "");
		panel.add(Box.createHorizontalStrut(84));
		// panel.add(Box.createHorizontalStrut(15));
		panel.add(new JLabel("ID"), "w 15!");
		panel.add(Box.createHorizontalStrut(1));
		panel.add(id, "w 40!");
		panel.add(find);
		panel.add(browse);
		panel.add(createNew, "wrap");
		// panel.add(Box.createHorizontalStrut(10), "wrap");
		// panel.add(createNew, ",wrap");

		remove
				.setToolTipText("Remove the reference to this object from the parent. Does not delete the refered object.");

		BoxLayout box = new BoxLayout(this, BoxLayout.PAGE_AXIS);
		setLayout(box);
		// SwingUtil.setSize(this, 400,);
		// setPreferredSize(preferredSize)
		// layout = new MigLayout("left,insets 0");
		// setLayout(layout);

		// add(panel, "w 100%,wrap");

		layout = new MigLayout("left,insets 0,gap 0");
		inside.setLayout(layout);

		content.setLayout(new BoxLayout(content, BoxLayout.LINE_AXIS));
		content.add(Box.createHorizontalStrut(5));
		content.add(inside);
		content.add(Box.createHorizontalStrut(5));
		add(content);

		inside.setBorder(BorderFactory.createEtchedBorder());

		inside.add(panel);

		createNew.addActionListener(this);
		find.addActionListener(this);
		browse.addActionListener(this);

		remove.addActionListener(this);

		id.addKeyListener(this);

	}

	private void setButtonBorder(Border border) {
		createNew.setBorder(border);
		find.setBorder(border);
		browse.setBorder(border);
		remove.setBorder(border);

	}

	// public void setEntityRefresh() throws Throwable {
	// getDeletePanel getDeletePanel = null;
	// DeletePanel deletePanel = null;
	// if (editor != null) {
	// getDeletePanel = (getDeletePanel) editor;
	// deletePanel = getDeletePanel.getDeletePanel();
	// showPanelDiscardEditor(deletePanel);
	// }
	//
	// String fieldURI = parentEditor.getEntityURI() + "/" + uriFieldName;
	// Response response = parentEditor.getClient().get(fieldURI);
	//
	// // if no child was found, exit the constructor
	// if (response.getStatus().getCode() != 200)
	// return;
	//
	// String childURI = response.getEntity().getText();
	//
	// getChildEditor();
	// editor.loadEntity(childURI);
	// hidePanelShowChildEditor();
	// }

	public void setEntity(Object object) throws Throwable {
		if (object == null)
			return;

		getChildEditor();
		editor.setEntity(object);
		hidePanelShowChildEditor();

	}

	@Override
	public void actionPerformed(ActionEvent e) {
		try {
			Object source = e.getSource();

			getDeletePanel getDeletePanel = null;
			DeletePanel deletePanel = null;
			if (editor != null) {
				getDeletePanel = (getDeletePanel) editor;
				deletePanel = getDeletePanel.getDeletePanel();
			}

			if (source == createNew) {
				getChildEditor();
				EditorUtil.showUpdatePanel();
				editor.createNew();

				// add it to the parent field - post
				addObjecToField();
				EditorUtil.hideUpdatePanel();
				return;
			}

			if (source == remove) {

				// remove from parent field - delete
				String fieldURI = parentEditor.getEntityURI() + "/"
						+ uriFieldName;
				EditorUtil.showUpdatePanel();
				Response response = parentEditor.getClient().delete(fieldURI);
				EditorUtil.hideUpdatePanel();
				if (response.getStatus().getCode() != 200)
					throw new RuntimeException("Error deleting field "
							+ uriFieldName + ". "
							+ response.getEntity().getText());

				showPanelDiscardEditor(deletePanel);

				return;
			}

			if (deletePanel != null)
				if (source == deletePanel.getDelete()) {
					if (deletePanel.isDeleted())
						showPanelDiscardEditor(deletePanel);

					return;
				}

			if (deletePanel != null)
				if (source == deletePanel.getDeleteAll()) {
					if (deletePanel.isDeleted())
						showPanelDiscardEditor(deletePanel);

					return;
				}

			if (source == find) {
				EditorUtil.showUpdatePanel();
				findAndSetChildObjectToField();
				EditorUtil.hideUpdatePanel();
				return;
			}
			if (source == browse) {
				dialog = new JDialog();
				dialog.setTitle("Select from List:");
				dialog.setModal(true);

				PagedListPanel pagedListPanel = new PagedListPanel(parentEditor
						.getUriProvider());

				getChildEditor();

				String entURI = editor.getClassURI();
				pagedListPanel.setBaseClassURI(entURI + "?detailed&size=30");
				pagedListPanel.setSelectionListener(this);

				dialog.add(pagedListPanel);
				dialog.pack();
				// dialog.setResizable(false);
				dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);

				dialog.setVisible(true);
			}
		} catch (Throwable t) {
			EditorUtil.hideUpdatePanel();
			t.printStackTrace();
			JOptionPane.showMessageDialog(this, t.getMessage(), "Error",
					JOptionPane.ERROR_MESSAGE);
		}

	}

	protected void findAndSetChildObjectToField() throws NoSuchMethodException,
			InstantiationException, IllegalAccessException,
			InvocationTargetException, Throwable, IOException {
		String text = id.getText();
		Integer findID = null;
		try {
			findID = Integer.valueOf(text);
		} catch (Throwable t) {
			EditorUtil.hideUpdatePanel();
			t.printStackTrace();
			JOptionPane.showMessageDialog(this, "Invalid ID", "Error",
					JOptionPane.ERROR_MESSAGE);
			return;
		}

		getChildEditor();

		String entURI = editor.getClassURI() + "/" + findID;

		editor.loadEntity(entURI);

		addObjecToField();
	}

	private void showPanelDiscardEditor(DeletePanel deletePanel) {
		deletePanel.remove(remove);
		deletePanel.removeActionListeners();
		inside.remove(editor);
		inside.add(panel);
		editor = null;
		// invalidate();
		revalidate();
		// repaint();
	}

	private void hidePanelShowChildEditor() {
		getDeletePanel getDeletePanel;
		DeletePanel deletePanel;
		inside.remove(panel);
		getDeletePanel = (getDeletePanel) editor;
		deletePanel = getDeletePanel.getDeletePanel();
		deletePanel.add(remove);
		deletePanel.setActionListeners(this);
		inside.add(editor);
		revalidate();
		// repaint();
	}

	protected void getChildEditor() throws NoSuchMethodException,
			InstantiationException, IllegalAccessException,
			InvocationTargetException {
		Constructor constructor = editorClass.getConstructor(URIProvider.class);
		editor = (SimpleEditor) constructor.newInstance(parentEditor
				.getUriProvider());

		editor.setFullBackground(getBackground());
		// editor.setBorder(getBorder());

		if (editor instanceof FilePathAware) {
			FilePathAware temp = (FilePathAware) editor;
			temp.setFilePathProvider(filePathProvider);
		}

	}

	@Override
	public void keyPressed(KeyEvent e) {
		if (e.getKeyCode() == KeyEvent.VK_ENTER) {
			try {
				findAndSetChildObjectToField();
			} catch (Throwable t) {
				EditorUtil.hideUpdatePanel();
				t.printStackTrace();
				JOptionPane.showMessageDialog(this, t.getMessage(), "Error",
						JOptionPane.ERROR_MESSAGE);
			}
		}

	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void selected(Object object) {

		try {
			EditorUtil.showUpdatePanel();
			getChildEditor();

			editor.setEntity(object);

			addObjecToField();

			dialog.setVisible(false);
			dialog = null;
			EditorUtil.hideUpdatePanel();
		} catch (Throwable t) {
			EditorUtil.hideUpdatePanel();
			t.printStackTrace();
			JOptionPane.showMessageDialog(this, t.getMessage(), "Error",
					JOptionPane.ERROR_MESSAGE);
		}

	}

	protected void addObjecToField() throws Throwable {
		// add it to the parent field - post
		String fieldURI = parentEditor.getEntityURI() + "/" + uriFieldName;
		String childURI = editor.getEntityURI();
		EditorUtil.showUpdatePanel();
		Response response = parentEditor.getClient().post(fieldURI,
				new StringRepresentation(childURI));
		EditorUtil.hideUpdatePanel();
		if (response.getStatus().getCode() != 201)
			throw new RuntimeException("Error adding field " + uriFieldName
					+ ". " + response.getEntity().getText());

		hidePanelShowChildEditor();
	}

	@Override
	public void setFilePathProvider(FilePathProvider provider) {
		this.filePathProvider = provider;

		if (editor != null && editor instanceof FilePathAware) {
			FilePathAware temp = (FilePathAware) editor;
			temp.setFilePathProvider(filePathProvider);
		}
	}

	public void setFullBackground(Color color) {
		panel.setBackground(color);
		setBackground(color);
		inside.setBackground(color);
		content.setBackground(color);

	}

}
